package drds.datasource.connection_pool.impl.holder;


import drds.datasource.connection_pool.api.SqlException;
import drds.datasource.connection_pool.impl.AbstractDataSource;
import drds.datasource.connection_pool.impl.PooledStatement;
import drds.datasource.connection_pool.util.JdbcUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 需要保存外面的用户线程获取的数据库的连接都是自动提交模式,否则需要对该连接进行回滚并回收
 */
@Slf4j
public final class ConnectionHolder {

    @Setter
    @Getter
    public final AbstractDataSource dataSource;
    @Setter
    @Getter
    public final long connectionId;
    @Setter
    @Getter
    public final Connection connection;
    @Setter
    @Getter
    public final long connectTimeMillis;
    @Setter
    @Getter
    public final List<drds.datasource.connection_pool.api.Statement> statementList = new ArrayList<drds.datasource.connection_pool.api.Statement>(2);
    @Setter
    @Getter
    public final boolean defaultAutoCommit;

    @Setter
    @Getter
    public final ReentrantLock lock = new ReentrantLock();

    @Setter
    @Getter
    public volatile long lastActiveTimeMillis;
    @Setter
    @Getter
    public volatile long lastKeepTimeMillis;
    @Setter
    @Getter
    public volatile long lastValidTimeMillis;
    @Setter
    @Getter
    public long useCount = 0;

    @Setter
    @Getter
    public boolean underlyingAutoCommit;
    @Setter
    @Getter
    public boolean discard = false;

    @Setter
    @Getter
    public long lastNotEmptyWaitNanos;

    public ConnectionHolder(AbstractDataSource dataSource, Connection connection) throws SqlException {
        this.dataSource = dataSource;
        this.connection = connection;
        this.connectionId = dataSource.createConnectionId();
        //
        this.connectTimeMillis = System.currentTimeMillis();
        this.lastActiveTimeMillis = connectTimeMillis;
        /**
         * 要求必须是自动提交
         */
        try {
            if (!connection.getAutoCommit()) {
                connection.setAutoCommit(true);
            }
            this.defaultAutoCommit = connection.getAutoCommit();
            this.underlyingAutoCommit = defaultAutoCommit;
        } catch (SQLException e) {
            JdbcUtils.log(log, "setAutoCommit(true)", e);
            throw new SqlException(e);
        }
    }


    public void addPooledStatement(PooledStatement pooledStatement) {
        lock.lock();
        try {
            statementList.add(pooledStatement);
        } finally {
            lock.unlock();
        }
    }

    public void removePooledStatement(PooledStatement pooledStatement) {
        lock.lock();
        try {
            statementList.remove(pooledStatement);
        } finally {
            lock.unlock();
        }
    }


    public void incrementUseCount() {
        useCount++;
    }


    public void reset() throws SQLException {
        /**
         * 恢复为自动提交模式
         */
        if (underlyingAutoCommit != defaultAutoCommit) {
            connection.setAutoCommit(defaultAutoCommit);
            underlyingAutoCommit = defaultAutoCommit;
        }
        //
        lock.lock();
        try {
            for (drds.datasource.connection_pool.api.Statement statement : statementList) {
                statement.close();
            }
            statementList.clear();
        } finally {
            lock.unlock();
        }
        connection.clearWarnings();
    }


}
